home *** CD-ROM | disk | FTP | other *** search
/ Programming Windows (5th Edition) / Programming Windows, 5th ed. - Companion CD (097-0002183)(1999).iso / Chap17 / Justify2 / Justify2.c next >
Encoding:
C/C++ Source or Header  |  1998-10-09  |  17.5 KB  |  495 lines

  1. /*-----------------------------------------
  2.    JUSTIFY2.C -- Justified Type Program #2
  3.                  (c) Charles Petzold, 1998
  4.   -----------------------------------------*/
  5.  
  6. #include <windows.h>
  7. #include "resource.h"
  8.  
  9. #define OUTWIDTH 6       // Width of formatted output in inches
  10. #define LASTCHAR 127     // Last character code used in text
  11.  
  12. LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
  13.  
  14. TCHAR szAppName[] = TEXT ("Justify2") ;
  15.  
  16. int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
  17.                     PSTR szCmdLine, int iCmdShow)
  18. {
  19.      HWND     hwnd ;
  20.      MSG      msg ;
  21.      WNDCLASS wndclass ;
  22.      
  23.      wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
  24.      wndclass.lpfnWndProc   = WndProc ;
  25.      wndclass.cbClsExtra    = 0 ;
  26.      wndclass.cbWndExtra    = 0 ;
  27.      wndclass.hInstance     = hInstance ;
  28.      wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
  29.      wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
  30.      wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
  31.      wndclass.lpszMenuName  = szAppName ;
  32.      wndclass.lpszClassName = szAppName ;
  33.      
  34.      if (!RegisterClass (&wndclass))
  35.      {
  36.           MessageBox (NULL, TEXT ("This program requires Windows NT!"),
  37.                szAppName, MB_ICONERROR) ;
  38.           return 0 ;
  39.      }
  40.      
  41.      hwnd = CreateWindow (szAppName, TEXT ("Justified Type #2"),
  42.                           WS_OVERLAPPEDWINDOW,
  43.                           CW_USEDEFAULT, CW_USEDEFAULT,
  44.                           CW_USEDEFAULT, CW_USEDEFAULT,
  45.                           NULL, NULL, hInstance, NULL) ;
  46.      
  47.      ShowWindow (hwnd, iCmdShow) ;
  48.      UpdateWindow (hwnd) ;
  49.      
  50.      while (GetMessage (&msg, NULL, 0, 0))
  51.      {
  52.           TranslateMessage (&msg) ;
  53.           DispatchMessage (&msg) ;
  54.      }
  55.      return msg.wParam ;
  56. }
  57.  
  58. void DrawRuler (HDC hdc, RECT * prc)
  59. {
  60.      static int iRuleSize [16] = { 360, 72, 144, 72, 216, 72, 144, 72,
  61.                                    288, 72, 144, 72, 216, 72, 144, 72 } ;
  62.      int        i, j ;
  63.      POINT      ptClient ;
  64.      
  65.      SaveDC (hdc) ;
  66.      
  67.           // Set Logical Twips mapping mode
  68.      
  69.      SetMapMode (hdc, MM_ANISOTROPIC) ;
  70.      SetWindowExtEx (hdc, 1440, 1440, NULL) ;
  71.      SetViewportExtEx (hdc, GetDeviceCaps (hdc, LOGPIXELSX),
  72.                             GetDeviceCaps (hdc, LOGPIXELSY), NULL) ;
  73.      
  74.           // Move the origin to a half inch from upper left
  75.      
  76.      SetWindowOrgEx (hdc, -720, -720, NULL) ;
  77.      
  78.           // Find the right margin (quarter inch from right)
  79.      
  80.      ptClient.x = prc->right ;
  81.      ptClient.y = prc->bottom ;
  82.      DPtoLP (hdc, &ptClient, 1) ;
  83.      ptClient.x -= 360 ;
  84.      
  85.           // Draw the rulers
  86.      
  87.      MoveToEx (hdc, 0,               -360, NULL) ;
  88.      LineTo   (hdc, OUTWIDTH * 1440, -360) ;
  89.      MoveToEx (hdc, -360,               0, NULL) ;
  90.      LineTo   (hdc, -360,      ptClient.y) ;
  91.      
  92.      for (i = 0, j = 0 ; i <= ptClient.x && i <= OUTWIDTH * 1440 ;
  93.                          i += 1440 / 16, j++)
  94.      {
  95.           MoveToEx (hdc, i, -360, NULL) ;
  96.           LineTo   (hdc, i, -360 - iRuleSize [j % 16]) ;
  97.      }
  98.      
  99.      for (i = 0, j = 0 ; i <= ptClient.y ; i += 1440 / 16, j++)
  100.      {
  101.           MoveToEx (hdc, -360, i, NULL) ;
  102.           LineTo   (hdc, -360 - iRuleSize [j % 16], i) ;
  103.      }
  104.      
  105.      RestoreDC (hdc, -1) ;
  106. }
  107.  
  108. /*----------------------------------------------------------------------
  109.    GetCharDesignWidths:  Gets character widths for font as large as the
  110.                          original design size
  111.   ----------------------------------------------------------------------*/
  112.  
  113. UINT GetCharDesignWidths (HDC hdc, UINT uFirst, UINT uLast, int * piWidths)
  114. {
  115.      HFONT             hFont, hFontDesign ;
  116.      LOGFONT           lf ;
  117.      OUTLINETEXTMETRIC otm ;
  118.  
  119.      hFont = GetCurrentObject (hdc, OBJ_FONT) ;
  120.      GetObject (hFont, sizeof (LOGFONT), &lf) ;
  121.  
  122.           // Get outline text metrics (we'll only be using a field that is
  123.           //   independent of the DC the font is selected into)
  124.  
  125.      otm.otmSize = sizeof (OUTLINETEXTMETRIC) ;
  126.      GetOutlineTextMetrics (hdc, sizeof (OUTLINETEXTMETRIC), &otm) ;
  127.  
  128.           // Create a new font based on the design size
  129.  
  130.      lf.lfHeight = - (int) otm.otmEMSquare ;
  131.      lf.lfWidth  = 0 ;
  132.      hFontDesign = CreateFontIndirect (&lf) ;
  133.  
  134.           // Select the font into the DC and get the character widths
  135.  
  136.      SaveDC (hdc) ;
  137.      SetMapMode (hdc, MM_TEXT) ;
  138.      SelectObject (hdc, hFontDesign) ;
  139.  
  140.      GetCharWidth (hdc, uFirst, uLast, piWidths) ;
  141.      SelectObject (hdc, hFont) ;
  142.      RestoreDC (hdc, -1) ;
  143.  
  144.           // Clean up
  145.  
  146.      DeleteObject (hFontDesign) ;
  147.  
  148.      return otm.otmEMSquare ;
  149. }
  150.  
  151. /*---------------------------------------------------------------------
  152.    GetScaledWidths:  Gets floating point character widths for selected
  153.                      font size
  154.   ---------------------------------------------------------------------*/
  155.  
  156. void GetScaledWidths (HDC hdc, double * pdWidths)
  157. {
  158.      double  dScale ;
  159.      HFONT   hFont ;
  160.      int     aiDesignWidths [LASTCHAR + 1] ;
  161.      int     i ;
  162.      LOGFONT lf ;
  163.      UINT    uEMSquare ;
  164.  
  165.           // Call function above
  166.  
  167.      uEMSquare = GetCharDesignWidths (hdc, 0, LASTCHAR, aiDesignWidths) ;
  168.  
  169.           // Get LOGFONT for current font in device context
  170.  
  171.      hFont = GetCurrentObject (hdc, OBJ_FONT) ;
  172.      GetObject (hFont, sizeof (LOGFONT), &lf) ;
  173.  
  174.           // Scale the widths and store as floating point values
  175.  
  176.      dScale = (double) -lf.lfHeight / (double) uEMSquare ;
  177.  
  178.      for (i = 0 ; i <= LASTCHAR ; i++)
  179.           pdWidths[i] = dScale * aiDesignWidths[i] ;
  180. }
  181.  
  182. /*--------------------------------------------------------------
  183.    GetTextExtentFloat:  Calculates text width in floating point
  184.   --------------------------------------------------------------*/
  185.  
  186. double GetTextExtentFloat (double * pdWidths, PTSTR psText, int iCount)
  187. {
  188.      double dWidth = 0 ;
  189.      int    i ;
  190.  
  191.      for (i = 0 ; i < iCount ; i++)
  192.           dWidth += pdWidths [psText[i]] ;
  193.  
  194.      return dWidth ;
  195. }
  196.  
  197. /*------------------------------------------------------------------
  198.    Justify:  Based on design units for screen/printer compatibility
  199.   ------------------------------------------------------------------*/
  200.  
  201. void Justify (HDC hdc, PTSTR pText, RECT * prc, int iAlign)
  202. {
  203.      double dWidth, adWidths[LASTCHAR + 1] ;
  204.      int    xStart, yStart, cSpaceChars ;
  205.      PTSTR  pBegin, pEnd ;
  206.      SIZE   size ;
  207.  
  208.           // Fill the adWidths array with floating point character widths
  209.  
  210.      GetScaledWidths (hdc, adWidths) ;
  211.  
  212.      yStart = prc->top ;
  213.      do                            // for each text line
  214.      {
  215.           cSpaceChars = 0 ;        // initialize number of spaces in line
  216.  
  217.           while (*pText == ' ')    // skip over leading spaces
  218.                pText++ ;
  219.  
  220.           pBegin = pText ;         // set pointer to char at beginning of line
  221.           
  222.           do                       // until the line is known
  223.           {
  224.                pEnd = pText ;      // set pointer to char at end of line
  225.  
  226.                     // skip to next space 
  227.                
  228.                while (*pText != '\0' && *pText++ != ' ') ;
  229.  
  230.                if (*pText == '\0')
  231.                     break ;
  232.  
  233.                     // after each space encountered, calculate extents
  234.  
  235.                cSpaceChars++ ;
  236.                dWidth = GetTextExtentFloat (adWidths, pBegin, 
  237.                                                       pText - pBegin - 1) ;
  238.           }
  239.           while (dWidth < (double) (prc->right - prc->left)) ;
  240.           
  241.           cSpaceChars-- ;               // discount last space at end of line
  242.           
  243.           while (*(pEnd - 1) == ' ')    // eliminate trailing spaces
  244.           {
  245.                pEnd-- ;
  246.                cSpaceChars-- ;
  247.           }
  248.  
  249.                // if end of text and no space characters, set pEnd to end
  250.           
  251.           if (*pText == '\0' || cSpaceChars <= 0)
  252.                pEnd = pText ;
  253.  
  254.                // Now get integer extents
  255.  
  256.           GetTextExtentPoint32(hdc, pBegin, pEnd - pBegin, &size) ;
  257.           
  258.           switch (iAlign)               // use alignment for xStart
  259.           {
  260.           case IDM_ALIGN_LEFT:
  261.                xStart = prc->left ;
  262.                break ;
  263.                
  264.           case IDM_ALIGN_RIGHT:
  265.                xStart = prc->right - size.cx ;
  266.                break ;
  267.                
  268.           case IDM_ALIGN_CENTER:
  269.                xStart = (prc->right + prc->left - size.cx) / 2 ;
  270.                break ;
  271.                
  272.           case IDM_ALIGN_JUSTIFIED:
  273.                if (*pText != '\0' && cSpaceChars > 0)
  274.                     SetTextJustification (hdc,
  275.                                           prc->right - prc->left - size.cx,
  276.                                           cSpaceChars) ;
  277.                xStart = prc->left ;
  278.                break ;
  279.           }
  280.                // display the text
  281.           
  282.           TextOut (hdc, xStart, yStart, pBegin, pEnd - pBegin) ;
  283.  
  284.                // prepare for next line
  285.  
  286.           SetTextJustification (hdc, 0, 0) ;
  287.           yStart += size.cy ;
  288.           pText = pEnd ;
  289.      }
  290.      while (*pText && yStart < prc->bottom - size.cy) ;
  291. }
  292.  
  293. LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  294. {
  295.      static CHOOSEFONT cf ;
  296.      static DOCINFO    di = { sizeof (DOCINFO), TEXT ("Justify2: Printing") } ;
  297.      static int        iAlign = IDM_ALIGN_LEFT ;
  298.      static LOGFONT    lf ;
  299.      static PRINTDLG   pd ;
  300.      static TCHAR      szText[] = { 
  301.                               TEXT ("Call me Ishmael. Some years ago -- never ")
  302.                               TEXT ("mind how long precisely -- having little ")
  303.                               TEXT ("or no money in my purse, and nothing ")
  304.                               TEXT ("particular to interest me on shore, I ")
  305.                               TEXT ("thought I would sail about a little and ")
  306.                               TEXT ("see the watery part of the world. It is ")
  307.                               TEXT ("a way I have of driving off the spleen, ")
  308.                               TEXT ("and regulating the circulation. Whenever ")
  309.                               TEXT ("I find myself growing grim about the ")
  310.                               TEXT ("mouth; whenever it is a damp, drizzly ")
  311.                               TEXT ("November in my soul; whenever I find ")
  312.                               TEXT ("myself involuntarily pausing before ")
  313.                               TEXT ("coffin warehouses, and bringing up the ")
  314.                               TEXT ("rear of every funeral I meet; and ")
  315.                               TEXT ("especially whenever my hypos get such an ")
  316.                               TEXT ("upper hand of me, that it requires a ")
  317.                               TEXT ("strong moral principle to prevent me ")
  318.                               TEXT ("from deliberately stepping into the ")
  319.                               TEXT ("street, and methodically knocking ")
  320.                               TEXT ("people's hats off -- then, I account it ")
  321.                               TEXT ("high time to get to sea as soon as I ")
  322.                               TEXT ("can. This is my substitute for pistol ")
  323.                               TEXT ("and ball. With a philosophical flourish ")
  324.                               TEXT ("Cato throws himself upon his sword; I ")
  325.                               TEXT ("quietly take to the ship. There is ")
  326.                               TEXT ("nothing surprising in this. If they but ")
  327.                               TEXT ("knew it, almost all men in their degree, ")
  328.                               TEXT ("some time or other, cherish very nearly ")
  329.                               TEXT ("the same feelings towards the ocean with ")
  330.                               TEXT ("me.") } ;
  331.      BOOL              fSuccess ;
  332.      HDC               hdc, hdcPrn ;
  333.      HMENU             hMenu ;
  334.      int               iSavePointSize ;
  335.      PAINTSTRUCT       ps ;
  336.      RECT              rect ;
  337.      
  338.      switch (message)
  339.      {
  340.      case WM_CREATE:
  341.                // Initialize the CHOOSEFONT structure
  342.  
  343.           hdc = GetDC (hwnd) ;
  344.           lf.lfHeight = - GetDeviceCaps (hdc, LOGPIXELSY) / 6 ;
  345.           lf.lfOutPrecision = OUT_TT_ONLY_PRECIS ;
  346.           lstrcpy (lf.lfFaceName, TEXT ("Times New Roman")) ;
  347.           ReleaseDC (hwnd, hdc) ;
  348.  
  349.           cf.lStructSize    = sizeof (CHOOSEFONT) ;
  350.           cf.hwndOwner      = hwnd ;
  351.           cf.hDC            = NULL ;
  352.           cf.lpLogFont      = &lf ;
  353.           cf.iPointSize     = 120 ;
  354.  
  355.                // Set flags for TrueType only!
  356.  
  357.           cf.Flags          = CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS | 
  358.                               CF_TTONLY | CF_EFFECTS ;
  359.           cf.rgbColors      = 0 ;
  360.           cf.lCustData      = 0 ;
  361.           cf.lpfnHook       = NULL ;
  362.           cf.lpTemplateName = NULL ;
  363.           cf.hInstance      = NULL ;
  364.           cf.lpszStyle      = NULL ;
  365.           cf.nFontType      = 0 ;      
  366.           cf.nSizeMin       = 0 ;
  367.           cf.nSizeMax       = 0 ;
  368.   
  369.           return 0 ;
  370.  
  371.      case WM_COMMAND:
  372.           hMenu = GetMenu (hwnd) ;
  373.           
  374.           switch (LOWORD (wParam))
  375.           {
  376.           case IDM_FILE_PRINT:
  377.                     // Get printer DC
  378.  
  379.                pd.lStructSize = sizeof (PRINTDLG) ;
  380.                pd.hwndOwner   = hwnd ;
  381.               pd.Flags       = PD_RETURNDC | PD_NOPAGENUMS | PD_NOSELECTION ;
  382.  
  383.               if (!PrintDlg (&pd))
  384.                     return 0 ;
  385.  
  386.                if (NULL == (hdcPrn = pd.hDC))
  387.                {
  388.                     MessageBox (hwnd, TEXT ("Cannot obtain Printer DC"),
  389.                                 szAppName, MB_ICONEXCLAMATION | MB_OK) ;
  390.                     return 0 ;
  391.                }
  392.                     // Set margins for OUTWIDTH inches wide
  393.  
  394.                rect.left  = (GetDeviceCaps (hdcPrn, PHYSICALWIDTH) -
  395.                              GetDeviceCaps (hdcPrn, LOGPIXELSX) * OUTWIDTH) / 2 
  396.                            - GetDeviceCaps (hdcPrn, PHYSICALOFFSETX) ;
  397.                
  398.                rect.right = rect.left + 
  399.                              GetDeviceCaps (hdcPrn, LOGPIXELSX) * OUTWIDTH ;
  400.  
  401.                     // Set margins of 1 inch at top and bottom
  402.  
  403.                rect.top    = GetDeviceCaps (hdcPrn, LOGPIXELSY) -
  404.                              GetDeviceCaps (hdcPrn, PHYSICALOFFSETY) ;
  405.  
  406.                rect.bottom = GetDeviceCaps (hdcPrn, PHYSICALHEIGHT) - 
  407.                              GetDeviceCaps (hdcPrn, LOGPIXELSY) -
  408.                              GetDeviceCaps (hdcPrn, PHYSICALOFFSETY) ;
  409.  
  410.                     // Display text on printer
  411.  
  412.                SetCursor (LoadCursor (NULL, IDC_WAIT)) ;
  413.                ShowCursor (TRUE) ;
  414.  
  415.                fSuccess = FALSE ;
  416.  
  417.                if ((StartDoc (hdcPrn, &di) > 0) && (StartPage (hdcPrn) > 0))
  418.                {
  419.                          // Select font using adjusted lfHeight
  420.  
  421.                     iSavePointSize = lf.lfHeight ;
  422.                     lf.lfHeight = -(GetDeviceCaps (hdcPrn, LOGPIXELSY) *
  423.                                          cf.iPointSize) / 720 ;
  424.  
  425.                     SelectObject (hdcPrn, CreateFontIndirect (&lf)) ;
  426.                     lf.lfHeight = iSavePointSize ;
  427.  
  428.                          // Set text color 
  429.  
  430.                     SetTextColor (hdcPrn, cf.rgbColors) ;
  431.                
  432.                          // Display text
  433.  
  434.                     Justify (hdcPrn, szText, &rect, iAlign) ;
  435.  
  436.                     if (EndPage (hdcPrn) > 0)
  437.                     {
  438.                          fSuccess = TRUE ;
  439.                          EndDoc (hdcPrn) ;
  440.                     }
  441.                }
  442.                ShowCursor (FALSE) ;
  443.                SetCursor (LoadCursor (NULL, IDC_ARROW)) ;
  444.  
  445.                DeleteDC (hdcPrn) ;
  446.  
  447.                if (!fSuccess)
  448.                     MessageBox (hwnd, TEXT ("Could not print text"),
  449.                                 szAppName, MB_ICONEXCLAMATION | MB_OK) ;
  450.                return 0 ;
  451.  
  452.           case IDM_FONT:
  453.                if (ChooseFont (&cf))
  454.                     InvalidateRect (hwnd, NULL, TRUE) ;
  455.                return 0 ;
  456.                
  457.           case IDM_ALIGN_LEFT:
  458.           case IDM_ALIGN_RIGHT:
  459.           case IDM_ALIGN_CENTER:
  460.           case IDM_ALIGN_JUSTIFIED:
  461.                CheckMenuItem (hMenu, iAlign, MF_UNCHECKED) ;
  462.                iAlign = LOWORD (wParam) ;
  463.                CheckMenuItem (hMenu, iAlign, MF_CHECKED) ;
  464.                InvalidateRect (hwnd, NULL, TRUE) ;
  465.                return 0 ;
  466.           }
  467.           return 0 ;
  468.  
  469.      case WM_PAINT:
  470.           hdc = BeginPaint (hwnd, &ps) ;
  471.           
  472.           GetClientRect (hwnd, &rect) ;
  473.           DrawRuler (hdc, &rect) ;
  474.           
  475.           rect.left  += GetDeviceCaps (hdc, LOGPIXELSX) / 2 ;
  476.           rect.top   += GetDeviceCaps (hdc, LOGPIXELSY) / 2 ;
  477.           rect.right = rect.left + OUTWIDTH * GetDeviceCaps (hdc, LOGPIXELSX) ;
  478.  
  479.           SelectObject (hdc, CreateFontIndirect (&lf)) ;
  480.           SetTextColor (hdc, cf.rgbColors) ;
  481.           
  482.           Justify (hdc, szText, &rect, iAlign) ;
  483.           
  484.           DeleteObject (SelectObject (hdc, GetStockObject (SYSTEM_FONT)));
  485.           EndPaint (hwnd, &ps) ;
  486.           return 0 ;
  487.           
  488.      case WM_DESTROY:
  489.           PostQuitMessage (0) ;
  490.           return 0 ;
  491.      }
  492.      return DefWindowProc (hwnd, message, wParam, lParam) ;
  493. }
  494.  
  495.